#ifndef _csSharedPtr_h_
#define _csSharedPtr_h_

/********************************************************************
	created:	2009/11/05
	created:	5:11:2009   20:48
	filename: 	e:\csEngine\csCoreLib\src\common\csSharedPtr.h
	file path:	e:\csEngine\csCoreLib\src\common
	file base:	csSharedPtr
	file ext:	h
	author:		dongchengok
	
	purpose:	shared ptr, do not need base class ReferencedObject
*********************************************************************/
#include "csType.h"
#include "csSafeCounter.h"

template<typename T>
class csSharedPtr
{
public:

	csSharedPtr();
	template<typename Y> explicit csSharedPtr(Y* p);
	template<typename Y> csSharedPtr(const csSharedPtr<Y>& p);
	csSharedPtr(const csSharedPtr<T>& p);
	~csSharedPtr();

	T*				get() const;
	csSafeCounter*	getCounter() const;

	template<typename Y>
	void			operator =(Y* p);
	template<typename Y>
	void			operator =(const csSharedPtr<Y>& p);
	template<typename Y>
	bool			operator==(Y* rhs) const;
	template<typename Y>
	bool			operator==(const csSharedPtr<Y>& rhs) const;
	template<typename Y>
	bool			operator!=(Y* rhs) const;
	template<typename Y>
	bool			operator!=(const csSharedPtr<Y>& rhs) const;

	T*				operator->() const;
	T&				operator* () const;

	bool			isValid() const;

protected:
	T*				m_ptr;
	csSafeCounter*	m_pCounter;
};

//------------------------------------------------------------------------
template<typename T>
csSharedPtr<T>::csSharedPtr()
:m_ptr(csNULL)
,m_pCounter(csNULL)
{

}

//------------------------------------------------------------------------
template<typename T> template<typename Y>
csSharedPtr<T>::csSharedPtr(Y* p)
:m_ptr(p)
,m_pCounter(csNULL)
{
	if(m_ptr)
	{
		m_pCounter = csNEW csSafeCounter(1);
	}
}

//------------------------------------------------------------------------
template<typename T> template<typename Y>
csSharedPtr<T>::csSharedPtr(const csSharedPtr<Y>& p)
:m_ptr(p.get())
,m_pCounter(p.getCounter())
{
	if(m_ptr)
	{
		m_pCounter->increment();
	}
}

//------------------------------------------------------------------------
template<typename T>
csSharedPtr<T>::csSharedPtr(const csSharedPtr<T>& p)
:m_ptr(p.m_ptr)
,m_pCounter(p.m_pCounter)
{
	if(m_ptr)
	{
		m_pCounter->increment();
	}
}

//------------------------------------------------------------------------
template<typename T>
csSharedPtr<T>::~csSharedPtr()
{
	if(m_ptr)
	{
		m_pCounter->decrement();
		if(0==m_pCounter->getValue())
		{
			csDELETE m_ptr;
			csDELETE m_pCounter;
		}
	}
}

//------------------------------------------------------------------------
template<typename T> template<typename Y> void
csSharedPtr<T>::operator =(Y* p)
{
	if(m_ptr&&0==m_pCounter->decrement())
	{
		csDELETE m_ptr;
		csDELETE m_pCounter;
	}
	m_ptr = p;
	if(m_ptr)
	{
		m_pCounter = csNEW csSafeCounter(1);
	}
	else
	{
		m_pCounter = csNULL;
	}
}

//------------------------------------------------------------------------
template<typename T> template<typename Y> void
csSharedPtr<T>::operator =(const csSharedPtr<Y>& p)
{
	if(m_ptr&&0==m_pCounter->decrement())
	{
		csDELETE m_ptr;
		csDELETE m_pCounter;
	}
	m_ptr		= p.get();
	if(m_ptr)
	{
		m_pCounter = p.getCounter();
		m_pCounter->increment();
	}
	else
	{
		m_pCounter = csNULL;
	}
}

//------------------------------------------------------------------------
template<typename T> template<typename Y> bool
csSharedPtr<T>::operator==(Y* p) const
{
	return m_ptr==p;
}

//------------------------------------------------------------------------
template<typename T> template<typename Y> bool
csSharedPtr<T>::operator==(const csSharedPtr<Y>& p) const
{
	return m_ptr==p.get();
}

//------------------------------------------------------------------------
template<typename T> template<typename Y> bool
csSharedPtr<T>::operator!=(Y* p) const
{
	return m_ptr!=p;
}

//------------------------------------------------------------------------
template<typename T> template<typename Y> bool
csSharedPtr<T>::operator!=(const csSharedPtr<Y>& p) const
{
	return m_ptr!=p.get();
}

//------------------------------------------------------------------------
template<typename T> T*
csSharedPtr<T>::get() const
{
	return m_ptr;
}

//------------------------------------------------------------------------
template<typename T> csSafeCounter*
csSharedPtr<T>::getCounter() const
{
	return m_pCounter;
}

//------------------------------------------------------------------------
template<typename T> T*
csSharedPtr<T>::operator->() const
{
	csASSERT(m_ptr);
	return m_ptr;
}

//------------------------------------------------------------------------
template<typename T> T&
csSharedPtr<T>::operator* () const
{
	csASSERT(m_ptr);
	return *m_ptr;
}

//------------------------------------------------------------------------
template<typename T> bool
csSharedPtr<T>::isValid() const
{
	return (csNULL!=m_ptr);
}

#endif // _csSharedPtr_h_